package cn.actoncode.boot.module.ai.service.user;

import cn.actoncode.boot.framework.common.enums.UserTypeEnum;
import cn.actoncode.boot.framework.security.core.LoginUser;
import cn.actoncode.boot.framework.security.core.util.JwtUtil;
import cn.actoncode.boot.module.ai.controller.app.auth.vo.login.RegisterReqVO;
import cn.actoncode.boot.module.ai.controller.app.auth.vo.login.RegisterRespVO;
import cn.actoncode.boot.module.ai.controller.app.auth.vo.login.WebLoginReqVO;
import cn.actoncode.boot.module.ai.controller.app.auth.vo.login.WebLoginRespVO;
import cn.actoncode.boot.module.ai.dal.dataobject.user.MemberUserDO;
import cn.actoncode.boot.module.ai.dal.mapper.user.MemberUserMapper;
import cn.actoncode.boot.module.ai.dal.redis.auth.LoginUserRedisDAO;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static cn.actoncode.boot.framework.common.constant.Constants.TOKEN_EXPIRES_HOUR;
import static cn.actoncode.boot.framework.common.constant.Constants.TOKEN_SALT_LENGTH;
import static cn.actoncode.boot.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.actoncode.boot.module.ai.enums.DictionaryConstants.USER_STATE_FREEZE;
import static cn.actoncode.boot.module.ai.enums.DictionaryConstants.USER_STATE_LOCKED;
import static cn.actoncode.boot.module.ai.enums.ErrorCodeConstants.*;

/**
 * 用户 Service 实现类
 *
 * @author bin
 */
@Service
@Valid
@Slf4j
public class MemberUserServiceImpl implements MemberUserService {

    @Resource
    private MemberUserMapper memberUserMapper;

    @Resource
    private LoginUserRedisDAO loginUserRedisDAO;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    public RegisterRespVO register(RegisterReqVO reqVO) {

        //校验用户是否存在
        MemberUserDO user = memberUserMapper.getUserByUsername(reqVO.getUsername());
        if (null != user) {
            throw exception(USER_ALREADY_EXISTS_ERROR);
        }

        // 最后登录时间
        Long llts = System.currentTimeMillis();

        // 新增用户
        user = new MemberUserDO();
        user.setUsername(reqVO.getUsername());
        user.setPassword(encodePassword(reqVO.getPassword()));
        // 设置随机8位数的盐值
        user.setSalt(RandomStringUtils.randomAlphabetic(TOKEN_SALT_LENGTH));
        memberUserMapper.insert(user);

        return RegisterRespVO.builder()
                .token(JwtUtil.getToken(user.getId(), UserTypeEnum.MEMBER.getValue(),
                        llts, user.getSalt(), TOKEN_EXPIRES_HOUR))
                .userId(user.getId())
                .build();
    }

    @Override
    public WebLoginRespVO login(WebLoginReqVO reqVO) {

        //校验用户是否可登录
        MemberUserDO user = this.validate(reqVO.getUsername(), reqVO.getPassword());

        // 最后登录时间
        Long llts = System.currentTimeMillis();
        //添加用户信息至session
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(user.getId());
        loginUser.setName(user.getName());
        loginUser.setSalt(user.getSalt());
        loginUser.setLlts(llts);

        // 存入redis
        loginUserRedisDAO.set(loginUser);

        //返回登录信息
        WebLoginRespVO loginDTO = new WebLoginRespVO();
        loginDTO.setToken(JwtUtil.getToken(user.getId(), UserTypeEnum.MEMBER.getValue(), llts, user.getSalt(), TOKEN_EXPIRES_HOUR));
        loginDTO.setUserId(user.getId());
        loginDTO.setName(user.getName());
        loginDTO.setAvatar(user.getAvatar());
        loginDTO.setMobile(user.getMobile());
        return loginDTO;
    }

    private MemberUserDO validate(String username, String password) {
        // 校验账号是否存在
        MemberUserDO user = memberUserMapper.getUserByUsername(username);
        if (user == null) {
            throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
        }
        if (!this.isPasswordMatch(password, user.getPassword())) {
            throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
        }

        if (USER_STATE_FREEZE == user.getState()) {
            throw exception(USER_FREEZE);
        }

        if (USER_STATE_LOCKED == user.getState()) {
            throw exception(USER_LOCKED);
        }
        return user;
    }

    @Override
    public MemberUserDO getUserByUserId(Long userId) {
        return memberUserMapper.selectById(userId);
    }

    @Override
    public boolean isPasswordMatch(String rawPassword, String encodedPassword) {
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }

    /**
     * 对密码进行加密
     *
     * @param password 密码
     * @return 加密后的密码
     */
    private String encodePassword(String password) {
        return passwordEncoder.encode(password);
    }
}
